package plugin;

import Phase2.Node;
import java.util.List;
import java.util.ArrayList;
import org.junit.Assert;
public class BroadcastAlgorithm implements Visitor
{
	public BroadcastAlgorithm()
	{
		
	}

	/**
	 * Visitor to determine which nodes in a 
	 * tree broadcast to be sent to next from Node n
	 * @param n the Node to be used
	 * @param information the origin Node
	 * @pre information is of type Integer, information is the id of a node in the HyPeerWeb
	 * @post return a list of Node to which a tree broadcast would follow from Node n
	 * @see plugin.Visitor#visit(Phase2.Node, java.lang.Object)
	 */
	@Override
	public Object visit(Node n, Object information) throws InterruptedException
	{
		boolean rootAccess = false;
		Assert.assertTrue(information instanceof Integer);
		int origin = (Integer) information;
		assert origin >= 0 : "Invalid origin: " + origin;
		
		List<Node> targetList = new ArrayList<Node>();
		
		int currentNode = n.getId(rootAccess);
		int mask = this.generateMask(origin ^ currentNode);
		int temp = 0;
		for (Node node : n.getNeighbours(rootAccess))
		{
			temp = node.getId(rootAccess);
			if (((temp ^ origin) > (currentNode ^ origin)) && satisfiesMask(temp ^ origin, mask))
			{
				targetList.add(node);
			}
		}
		for (Node node : n.getUpPointers(rootAccess))
		{
			temp = node.getId(rootAccess);
			if (satisfiesMask(temp ^ origin, mask))
			{
				targetList.add(node);
			}
		}
		//System.out.println("Node " + n.getId() + " broadcast to: " + targetList.toString());
		return targetList;
	}
	
	private boolean satisfiesMask(int node, int mask) 
	{
		return (node & mask) != 0;
	}

	private int generateMask(int node)
	{
		if (node == 0)
		{
			return -1;
		}
		int result = node;
		int count = 0;
		while ((result & 1) != 1)
		{
			count++;
			result = result >>> 1;
		}
		
		result = ~(-1 << count);
		return result;
	}

}
